/*jshint esversion: 6 */ //credit to Brian on the forums for this framework! on('chat:message', function(msg) { if (msg.type != 'api') return; var parts = msg.content.split(' '); var command = parts.shift().substring(1); function ManhDist(token1,token2) { //Manhattan Distance in tiles between two units let AXCoord = token1.get("left"); let AYCoord = token1.get("top"); let BXCoord = token2.get("left"); let BYCoord = token2.get("top"); let diff = parseInt((Math.abs(AXCoord - BXCoord))+(Math.abs(AYCoord - BYCoord))); return (diff/70) } var turnorder; if (Campaign().get("turnorder") == "") turnorder = []; else turnorder = JSON.parse(Campaign().get("turnorder")); log(turnorder[0]) // Don't run if it's any other command if (command == 'combat') { if (parts.length < 2) { sendChat('SYSTEM', 'You must provide a selected token id and a target token id.'); return; } var selectedId = parts[0]; var targetId = parts[1]; // Grab tokens var selectedToken = getObj('graphic', selectedId); var targetToken = getObj('graphic', targetId); // Check if the objects aren't tokens or if the passed parameters aren't ids if (!selectedToken) { sendChat('SYSTEM', 'Selected token id not provided.'); return; } if (!targetToken) { sendChat('SYSTEM', 'Target token id not provided.'); return; } log(selectedToken.get('represents')); log(targetToken.get('represents')); //Check to make sure that the tokens represent characters if (selectedToken.get('represents') === "" || targetToken.get('represents') === ""){ sendChat('SYSTEM', 'Both tokens must be linked to characters in the journal!'); return; } // Get a variable to use as the "who" for sendChat var who = getObj('character', selectedToken.get('represents')); if (!who) { who = selectedToken.get('name'); } else { who = 'character|' + who.id; } var who2 = getObj('character', targetToken.get('represents')); if (!who2) { who2 = targetToken.get('name'); } else { who2 = 'character|' + who2.id; } var attacker = getObj('character', selectedToken.get('represents')); var defender = getObj('character', targetToken.get('represents')); let AName = attacker.get('name'); let DName = defender.get('name'); let Chatstr = AName + ' attacks ' + DName + '!\n'; //Grab basic stats let CurrHPA = findObjs({ characterid: attacker.id, name: "HP_current"})[0]; let CurrHPB = findObjs({ characterid: defender.id, name: "HP_current"})[0]; let CurrEXP = findObjs({ characterid: attacker.id, name: "EXP"})[0]; let LvA = findObjs({ characterid: attacker.id, name: "Level"})[0]; let InLvA = Number(LvA.get("current")); let LvB = findObjs({ characterid: defender.id, name: "Level"})[0]; let InLvB = Number(LvB.get("current")); let EXPA = Number(CurrEXP.get("current")); let IsPromoA = getAttrByName(attacker.id, 'isPromo'); let IsPromoB = getAttrByName(defender.id, 'isPromo'); let HPA = getAttrByName(attacker.id, 'hp_current'); let HPB = getAttrByName(defender.id, 'hp_current'); let StrA = getAttrByName(attacker.id, 'str_total'); let StrB = getAttrByName(defender.id, 'str_total'); let MagA = getAttrByName(attacker.id, 'mag_total'); let MagB = getAttrByName(defender.id, 'mag_total'); let SklA = getAttrByName(attacker.id, 'skl_total'); let SklB = getAttrByName(defender.id, 'skl_total'); let SpdA = getAttrByName(attacker.id, 'spd_total'); let SpdB = getAttrByName(defender.id, 'spd_total'); let LckA = getAttrByName(attacker.id, 'lck_total'); let LckB = getAttrByName(defender.id, 'lck_total'); let DefA = getAttrByName(attacker.id, 'def_total'); let DefB = getAttrByName(defender.id, 'def_total'); let ResA = getAttrByName(attacker.id, 'res_total'); let ResB = getAttrByName(defender.id, 'res_total'); //Grab weapon stats let WNameA = getAttrByName(attacker.id, 'f_WName'); let WNameB = getAttrByName(defender.id, 'f_WName'); let WTypeA = getAttrByName(attacker.id, 'f_WType'); let WTypeB = getAttrByName(defender.id, 'f_WType'); let MtA = getAttrByName(attacker.id, 'f_Mt'); let MtB = getAttrByName(defender.id, 'f_Mt'); let WtA = getAttrByName(attacker.id, 'f_Wt'); let WtB = getAttrByName(defender.id, 'f_Wt'); let Range1A = getAttrByName(attacker.id, 'f_Range1'); let Range1B = getAttrByName(defender.id, 'f_Range1'); let Range2A = getAttrByName(attacker.id, 'f_Range2'); let Range2B = getAttrByName(defender.id, 'f_Range2'); let WRankA = getAttrByName(attacker.id, 'f_WRank'); let WRankB = getAttrByName(defender.id, 'f_WRank'); log(WRankA); log(WRankB); let fIDA = findObjs({ characterid: attacker.id, name: "fid"})[0]; let fIDB = findObjs({ characterid: defender.id, name: "fid"})[0]; log(fIDA); log(fIDB); let UsesA; let UsesB; //check for no rows if (fIDA.get("current") == ""){ UsesA = 68932; log("No weapon! :0"); } else { UsesA = findObjs({ characterid: attacker.id, name: "repeating_weapons_"+fIDA.get("current")+"_Uses"},{ caseInsensitive: true })[0]; } if (fIDB.get("current") == ""){ UsesB = 68932; } else { UsesB = findObjs({ characterid: defender.id, name: "repeating_weapons_"+fIDB.get("current")+"_Uses"},{ caseInsensitive: true })[0]; } log(UsesA); log(UsesB); let StrengthsA = getAttrByName(attacker.id, 'f_Strengths'); let StrengthsB = getAttrByName(defender.id, 'f_Strengths'); let WeaknessA = getAttrByName(attacker.id, 'weaknesses'); let WeaknessB = getAttrByName(defender.id, 'weaknesses'); //Weapon exp let SwordEXP = findObjs({ characterid: attacker.id, name: "SwordEXP", type: "attribute"})[0]; let LanceEXP = findObjs({ characterid: attacker.id, name: "LanceEXP", type: "attribute"})[0]; let AxeEXP = findObjs({ characterid: attacker.id, name: "AxeEXP", type: "attribute"})[0]; let BowEXP = findObjs({ characterid: attacker.id, name: "BowEXP", type: "attribute"})[0]; let DaggerEXP = findObjs({ characterid: attacker.id, name: "GunEXP", type: "attribute"})[0]; let GunEXP = findObjs({ characterid: attacker.id, name: "GunEXP", type: "attribute"})[0]; let DarkEXP = findObjs({ characterid: attacker.id, name: "DarkEXP", type: "attribute"})[0]; let LightEXP = findObjs({ characterid: attacker.id, name: "LightEXP", type: "attribute"})[0]; let AnimaEXP = findObjs({ characterid: attacker.id, name: "AnimaEXP", type: "attribute"})[0]; let StoneEXP = findObjs({ characterid: attacker.id, name: "StoneEXP", type: "attribute"})[0]; let StaffEXP = findObjs({ characterid: attacker.id, name: "StaffEXP", type: "attribute"})[0]; //Hit/crit/avo/dod let HitA = getAttrByName(attacker.id, 'hit'); let HitB = getAttrByName(defender.id, 'hit'); let CritA = getAttrByName(attacker.id, 'crit'); let CritB = getAttrByName(defender.id, 'crit'); let AvoA = getAttrByName(attacker.id, 'avo'); let AvoB = getAttrByName(defender.id, 'avo'); let DdgA = getAttrByName(attacker.id, 'lck_total'); let DdgB = getAttrByName(defender.id, 'lck_total'); //Grab weapon ranks let SwordUA = getAttrByName(attacker.id, 'SwordU'); let LanceUA = getAttrByName(attacker.id, 'LanceU'); let AxeUA = getAttrByName(attacker.id, 'AxeU'); let BowUA = getAttrByName(attacker.id, 'BowU'); let DaggerUA = getAttrByName(attacker.id, 'DaggerU'); let GunUA = getAttrByName(attacker.id, 'GunU'); let AnimaUA = getAttrByName(attacker.id, 'AnimaU'); let LightUA = getAttrByName(attacker.id, 'LightU'); let DarkUA = getAttrByName(attacker.id, 'DarkU'); let StoneUA = getAttrByName(attacker.id, 'StoneU'); let StaffUA = getAttrByName(attacker.id, 'StaffU'); log(SwordUA); let SwordUB = getAttrByName(defender.id, 'SwordU'); let LanceUB = getAttrByName(defender.id, 'LanceU'); let AxeUB = getAttrByName(defender.id, 'AxeU'); let BowUB = getAttrByName(defender.id, 'BowU'); let DaggerUB = getAttrByName(defender.id, 'DaggerU'); let GunUB = getAttrByName(defender.id, 'GunU'); let AnimaUB = getAttrByName(defender.id, 'AnimaU'); let LightUB = getAttrByName(defender.id, 'LightU'); let DarkUB = getAttrByName(defender.id, 'DarkU'); let StoneUB = getAttrByName(defender.id, 'StoneU'); let StaffUB = getAttrByName(defender.id, 'StaffU'); const PhysWepTypes = ["Sword/Katana","Lance/Nagin.","Axe/Club","Bow/Yumi","Dagger/Shurik.","Stones/Other"]; const MWepTypes = ["Anima Magic","Light Magic","Dark Magic"]; const WepTypes = ["Sword/Katana","Lance/Nagin.","Axe/Club","Bow/Yumi","Dagger/Shurik.","Firearm/Taneg.","Anima Magic","Light Magic","Dark Magic","Stones/Other","Staves/Rods"]; const MagWeps = ["Levin Sword","Bolt Naginata","Bolt Axe","Shining Bow","Flame Shuriken"]; const PhysWeps = ["Flame Glaive","Light Rapier","Shadow Hammer"]; const WepRanks = [SwordEXP,LanceEXP,AxeEXP,BowEXP,DaggerEXP,GunEXP,AnimaEXP,LightEXP,DarkEXP,StoneEXP,StaffEXP]; const WepUA = [SwordUA,LanceUA,AxeUA,BowUA,DaggerUA,GunUA,AnimaUA,LightUA,DarkUA,StoneUA,StaffUA]; const WepUB = [SwordUB,LanceUB,AxeUB,BowUB,DaggerUB,GunUB,AnimaUB,LightUB,DarkUB,StoneUB,StaffUB]; let DmgtypeA; let DmgtypeB; let DmgA; let DmgB; let DoubleA = false; let DoubleB = false; let QuadA = false; let QuadB = false; let CanAttackA = true; let CanAttackB = true; //Weapon Rank threshold values let WRankA_num; let WRankB_num; const LRanks = [{num: 0, rank: "E"},{num: 30, rank: "D"},{num: 70, rank: "C"},{num: 120, rank: "B"},{num: 180, rank: "A"},{num: 250, rank: "S"},{num: 999, rank: "UU"}]; //check for which rank for (var h in LRanks){ log(LRanks[h]); if (LRanks[h].rank == WRankA){ WRankA_num = LRanks[h].num; } } for (var j in LRanks){ log(LRanks[j]); if (LRanks[j].rank == WRankB){ WRankB_num = LRanks[j].num; } } log("Numerical weapon rank is " + WRankA_num); //Check to see if the weapon is usable if ((WepUA[WepTypes.indexOf(WTypeA)] == 1) && (WepRanks[WepTypes.indexOf(WTypeA)].get("current") >= WRankA_num)){ log("Attacker's weapon is usable!"); } else { log("Attacker's weapon is not usable!"); CanAttackA = false; } if ((WepUB[WepTypes.indexOf(WTypeB)] == 1) && (WepRanks[WepTypes.indexOf(WTypeB)].get("current") >= WRankB_num)){ log("Defender's weapon is usable!"); } else { log("Defender's weapon is not usable!"); CanAttackB = false; } //Check for weapon effectiveness- HAS TO BE BEFORE stat targeting calcs so it can factor in Mt. if ( ( StrengthsA.includes("Beast") && WeaknessB.includes("Beast")) || ( StrengthsA.includes("Flier") && WeaknessB.includes("Flier")) || ( StrengthsA.includes("Dragon") && WeaknessB.includes("Dragon")) || ( StrengthsA.includes("Armor") && WeaknessB.includes("Armor"))){ MtA *= 3; Chatstr += "Attacker has weapon effectiveness! \n"; } if ( ( StrengthsB.includes("Beast") && WeaknessA.includes("Beast")) || ( StrengthsB.includes("Flier") && WeaknessA.includes("Flier")) || ( StrengthsB.includes("Dragon") && WeaknessA.includes("Dragon")) || ( StrengthsB.includes("Armor") && WeaknessA.includes("Armor"))){ MtB *= 3; Chatstr += "Defender has weapon effectiveness! \n"; } //Targeted stat if ( (PhysWepTypes.includes(WTypeA))||(PhysWeps.includes(WNameA)) ){ DmgtypeA = "Physical"; DmgA = (StrA + MtA) - DefB; } else if ( (MWepTypes.includes(WTypeA))||(MagWeps.includes(WNameA)) ){ DmgtypeA = "Magical"; DmgA = (MagA + MtA) - ResB; } else if (WTypeA == "Firearm/Taneg.") { DmgtypeA = "Firearm"; DmgA = MtA - DefB; } else { DmgtypeA = "Healing"; DmgA = 0; Chatstr += "Unit cannot attack!"; sendChat("System","Unit cannot attack!"); return; } if (DmgA < 0){ DmgA = 0; } log(DmgtypeA); log(DmgA); if ( (PhysWepTypes.includes(WTypeB))||(PhysWeps.includes(WNameB)) ){ DmgtypeB = "Physical"; DmgB = (StrB + MtB) - DefA; } else if ( (MWepTypes.includes(WTypeB))||(MagWeps.includes(WNameB)) ){ DmgtypeB = "Magical"; DmgB = (MagB + MtB) - ResA; } else if (WTypeB == "Firearm/Taneg."){ DmgtypeB = "Firearm"; DmgB = MtB - DefA; } else { DmgtypeB = "Healing"; DmgB = 0; //Set damage to 0 so you don't accidentally heal the enemy; CanAttackB = false; } if (DmgB < 0){ DmgB = 0; } //check for doubling/braves if ( (SpdA - WtA) - (SpdB - WtB) > 5 || WNameA.toLowerCase().includes("brave")){ DoubleA = true; log("Attacker can double!"); if ( (SpdA - WtA) - (SpdB - WtB) > 5 && WNameA.toLowerCase().includes("brave")){ QuadA = true; log("Attacker can quad!"); } } if ( (SpdB - WtB) - (SpdA - WtA) > 5 || WNameB.toLowerCase().includes("brave")){ DoubleB = true; log("Defender can double!"); if ( (SpdB - WtB) - (SpdA - WtA) > 5 && WNameB.toLowerCase().includes("brave")){ QuadB = true; log("Defender can quad!"); } } //Check for WTA let WIndexA = WepTypes.indexOf(WTypeA)+ 1; let WIndexB = WepTypes.indexOf(WTypeB)+ 1; let WIN = WepTypes.indexOf(WTypeA); let CurrWR = WepRanks[WIN]; let CWRVal = Number(CurrWR.get("current")); //Assume number because it's a numerical input log(CurrWR); log(CWRVal); if( (WIndexA == 1 && WIndexB == 3) || (WIndexA == 3 && WIndexB == 2) || (WIndexA == 2 && WIndexB == 1) || (WIndexA == 4 && WIndexB == 5) || (WIndexA == 5 && WIndexB == 6) || (WIndexA == 6 && WIndexB == 4) || (WIndexA == 7 && WIndexB == 8) || (WIndexA == 8 && WIndexB == 9) || (WIndexA == 9 && WIndexB == 7)) { DmgA +=1; HitA +=15; DmgB -= 1; HitB -=15; Chatstr += "Attacker has WTA! \n"; } if( (WIndexA == 3 && WIndexB == 1) || (WIndexA == 2 && WIndexB == 3) || (WIndexA == 1 && WIndexB == 2) || (WIndexA == 5 && WIndexB == 4) || (WIndexA == 6 && WIndexB == 5) || (WIndexA == 4 && WIndexB == 6) || (WIndexA == 8 && WIndexB == 7) || (WIndexA == 9 && WIndexB == 8) || (WIndexA == 7 && WIndexB == 9)) { DmgA -=1; HitA -=15; DmgB += 1; HitB +=15; Chatstr += "Defender has WTA! \n"; } if (DmgA < 0){ DmgA = 0; } if (DmgB < 0){ DmgB = 0; } if (typeof(UsesA) === "object"){ function DecUsesA() { UsesA.setWithWorker({current: Number(UsesA.get("current")) - 2}); } log("Is an object!"); } else { log("Not an object!"); function DecUsesA() { UsesA -= 2; } } if (typeof(UsesB) === "object"){ function DecUsesB() { UsesA.setWithWorker({current: Number(UsesB.get("current")) - 1}); } log("Is an object!"); } else { log("Not an object!"); function DecUsesB() { UsesB -= 2; } } let SkillsA = findObjs({ characterid: attacker.id, type: "ability"}); for (var i in SkillsA){ SkillsA[i] = SkillsA[i].get("action"); SkillsA[i] = JSON.parse(SkillsA[i]) } log(SkillsA) let SkillsB = findObjs({ characterid: defender.id, type: "ability"}); for (var i in SkillsB){ SkillsB[i] = SkillsB[i].get("action"); SkillsB[i] = JSON.parse(SkillsB[i]) } log(SkillsB) //Skills system! :^) /*Here is an example of Speedtaker so I don't have to keep checking back to see what I used: { "name": "Speedtaker", "triggertime": "before", "u_wepreq": ["Sword/Katana","Lance/Nagin.","Axe/Club","Bow/Yumi","Dagger/Shurik.","Firearm/Taneg.","Anima Magic","Light Magic","Dark Magic","Stones/Other","Staves/Rods"], "e_wepreq": ["Sword/Katana","Lance/Nagin.","Axe/Club","Bow/Yumi","Dagger/Shurik.","Firearm/Taneg.","Anima Magic","Light Magic","Dark Magic","Stones/Other","Staves/Rods"], "whotriggered": "either", "radius_effect": "none", "physmagcond": false, "killcond": true, "rng": "any", "rngmod": "none", "u_healfactor": 0, "e_healfactor": 0, "u_hitmod": 0, "e_hitmod": 0, "u_critmod": 0, "e_critmod": 0, "u_avomod": 0, "e_avomod": 0, "u_ddgmod": 0, "e_ddgmod": 0, "physmag": false, "u_damagemod": "0", "e_damagemod": "0", "u_stat_target": "Spd", "e_stat_target": "none", "u_stat_targetmod": "2", "e_stat_targetmod": 0, "children_skills": [] } */ //stat initializations- technically, these do nothing in the main function because ~block scope~ let user; let RNGSklU; let RNGLuckU; let CurrHPU; let CurrHPE; let HPU; let HPE; let StrU; let StrE; let MagU; let MagE; let SklU; let SklE; let SpdU; let SpdE; let LckU; let LckE; let DefU; let DefE; let ResU; let ResE; let HitU; let HitE; let CritU; let CritE; let AvoU; let AvoE; let DdgU; let DdgE; let DmgU; let DmgE; let DmgtypeU; let DmgtypeE; let PhysmagU; let PhysmagE; let PhysmaginvU; let PhysmaginvE; let StattargetU; let StattargetE; let Dmg_U; let Dmg_E; function Skill(userid,targetid,obj,triggertime) { //haha END ME if (typeof obj != "object"){ log("obj is not an object :(") return; } if ((triggertime == obj.triggertime) && (((obj.whotriggered == "attacker") && (userid == attacker.id)) || ((obj.whotriggered == "defender") && (userid == defender.id)) || (obj.whotriggered == "either"))) { log("Okay, first barrier passed") if ((userid == attacker.id) && (obj.u_wepreq.indexOf(WTypeA) != -1) && (obj.e_wepreq.indexOf(WTypeB) != -1)) { //obj.u_wepreq is a list of weapon types (to account for Aegis/Pavise & other similar skills) //just change "any" to a list of all weapon types, I guess log("Skill user is attacker"); user = "attacker"; RNGSklU = SklA; RNGLuckU = LckA; CurrHPU = CurrHPA; CurrHPE = CurrHPB; DmgtypeU = DmgtypeA; DmgtypeE = DmgtypeB; Usertoken = selectedToken; Dmg_U = DmgA; //just for expressions'sake Dmg_E = DmgB; } else if ((userid == defender.id) && (obj.u_wepreq.indexOf(WTypeB) != -1) && (obj.e_wepreq.indexOf(WTypeA) != -1)) { user = "defender"; log("Skill user is defender") RNGSklU = SklB; RNGLuckU = LckB; CurrHPU = CurrHPB; CurrHPE = CurrHPA; DmgtypeU = DmgtypeB; DmgtypeE = DmgtypeA; Usertoken = targetToken; Dmg_U = DmgB; //just for expressions'sake Dmg_E = DmgA; } else { log("You probably don't have the right weapons") return; } log("DamageU is" + Dmg_U); //stat definitions HPU = findObjs({ characterid: userid, name: "HP_bd" })[0]; HPE = findObjs({ characterid: targetid, name: "HP_bd" })[0]; StrU = findObjs({ characterid: userid, name: "Str_bd" })[0]; StrE = findObjs({ characterid: targetid, name: "Str_bd" })[0]; MagU = findObjs({ characterid: userid, name: "Mag_bd" })[0]; MagE = findObjs({ characterid: targetid, name: "Mag_bd" })[0]; SklU = findObjs({ characterid: userid, name: "Skl_bd" })[0]; SklE = findObjs({ characterid: targetid, name: "Skl_bd" })[0]; SpdU = findObjs({ characterid: userid, name: "Spd_bd" })[0]; SpdE = findObjs({ characterid: targetid, name: "Spd_bd" })[0]; LckU = findObjs({ characterid: userid, name: "Lck_bd" })[0]; LckE = findObjs({ characterid: targetid, name: "Lck_bd" })[0]; DefU = findObjs({ characterid: userid, name: "Def_bd" })[0]; DefE = findObjs({ characterid: targetid, name: "Def_bd" })[0]; ResU = findObjs({ characterid: userid, name: "Res_bd" })[0]; ResE = findObjs({ characterid: targetid, name: "Res_bd" })[0]; //nice stat-variables for use in expressions and such let HP_StatU = getAttrByName(userid, 'hp_total'); let HP_StatE = getAttrByName(targetid, 'hp_total'); let Str_StatU = getAttrByName(userid, 'str_total'); let Str_StatE = getAttrByName(targetid, 'str_total'); let Mag_StatU = getAttrByName(userid, 'mag_total'); let Mag_StatE = getAttrByName(targetid, 'mag_total'); let Skl_StatU = getAttrByName(userid, 'skl_total'); let Skl_StatE = getAttrByName(targetid, 'skl_total'); let Spd_StatU = getAttrByName(userid, 'spd_total'); let Spd_StatE = getAttrByName(targetid, 'spd_total'); let Lck_StatU = getAttrByName(userid, 'lck_total'); let Lck_StatE = getAttrByName(targetid, 'lck_total'); let Def_StatU = getAttrByName(userid, 'def_total'); let Def_StatE = getAttrByName(targetid, 'def_total'); let Res_StatU = getAttrByName(userid, 'res_total'); let Res_StatE = getAttrByName(targetid, 'res_total'); let rng; if (obj.rng == "Skill") { rng = RNGSklU; } if (obj.rng == "Luck") { rng = RNGLckU; } log(obj.rng) //actual skill function function skillMain(){ //PhysmagE if (DmgtypeE == "Physical" || DmgtypeE == "Firearm") { PhysmagE = getAttrByName(targetid, "str_total"); PhysmaginvE = getAttrByName(targetid, "mag_total"); //inv for stuff like Ignis log(targetid) } else { PhysmagE = getAttrByName(targetid, "mag_total"); PhysmaginvE = getAttrByName(targetid, "str_total"); } //I would add a def/res parameter, but I'm just going to be lazy and use the defense AND resistance definition for Luna. log("PhysmagE is " + PhysmagE) //PhysmagU if (DmgtypeU == "Physical" || DmgtypeU == "Firearm") { PhysmagU = getAttrByName(userid, "str_total"); PhysmaginvU = getAttrByName(userid, "mag_total"); log(targetid) } else { PhysmagU = getAttrByName(userid, "mag_total"); PhysmaginvU = getAttrByName(userid, "str_total"); } log("PhysmagU is " + PhysmagU) /* Parse damage and HP modifiers- normally eval() is incredibly dangerous and usually Shouldn't Be Used Under Any Circumstance Ever, but the Roll20 API sandboxes it, so I think it should be alright. Oh well!*/ let DamagemodU = eval(obj.u_damagemod); log("Damage mod is " + DamagemodU) let DamagemodE = eval(obj.e_damagemod); let HealmodU = parseInt(eval(obj.u_healfactor)); let HealmodE = parseInt(eval(obj.e_healfactor)); log("HealmodU is" + HealmodU) let statnames = ["HP", "Str", "Mag", "Skl", "Spd", "Lck", "Def", "Res"]; //determining the actual stat target if (obj.u_stat_target || obj.e_stat_target != "none") { for (var r in statnames) { if (obj.u_stat_target == statnames[r]) { StattargetU = eval(statnames[r] + "U"); } if (obj.e_stat_target == statnames[r]) { StattargetE = eval(statnames[r] + "U"); } } } let StattargetmodU = eval(obj.u_stat_targetmod); let StattargetmodE = eval(obj.e_stat_targetmod); if (obj.u_stat_target != "none"){ StattargetU.setWithWorker({ current: Number(StattargetU.get("current")) + Number(StattargetmodU) }); log("Set targeted stat to "+ StattargetU.get("current")); } if (obj.e_stat_target != "none"){ StattargetE.setWithWorker({ current: Number(StattargetE.get("current")) + Number(StattargetmodE) }); log("Set targeted stat to "+ StattargetE.get("current")); } if (userid == attacker.id) { log("Damage before is " + DmgA) DmgA += DamagemodU; log("Damage after is " + DmgA) DmgB += DamagemodE; HitA += obj.u_hitmod; HitB += obj.e_hitmod; CritA += obj.u_critmod; CritB += obj.e_critmod; AvoA += obj.u_avomod; AvoB += obj.e_avomod; DdgA += obj.u_ddgmod; DdgB += obj.e_ddgmod; HPA = parseInt(HPA) + HealmodU; //this has to be here because sometimes it'll be stupid and overflow if it's not >:( HPB = parseInt(HPB) + HealmodE; } else { DmgB += DamagemodU; DmgA += DamagemodE; HitB += obj.u_hitmod; HitA += obj.e_hitmod; CritB += obj.u_critmod; CritA += obj.e_critmod; AvoB += obj.u_avomod; AvoA += obj.e_avomod; DdgB += obj.u_ddgmod; DdgA += obj.e_ddgmod; HPB = parseInt(HPB) + HealmodU; HPA = parseInt(HPA) + HealmodE; } log(HPA) if (obj.radius != 0){ //tortured screaming let tokenInRadius = filterObjs(function(token) { if ((token.get('type') !== 'graphic' || token.get('subtype') !== 'token' || token.get('represents') == "") || ManhDist(Usertoken,token) > obj.radius || token.get("represents") == Usertoken.get("represents")) return false; else return true; }); log("Tokens in radius are: ") for (var i in tokenInRadius){ log(tokenInRadius[i]) //stat targets let char = tokenInRadius[i].get("represents") let HPcurrC = findObjs({ characterid: char, name: "HP_current"})[0]; let StrC = findObjs({ characterid: char, name: "Str_bd"})[0]; let MagC = findObjs({ characterid: char, name: "Mag_bd"})[0]; let SklC = findObjs({ characterid: char, name: "Skl_bd"})[0]; let SpdC = findObjs({ characterid: char, name: "Spd_bd"})[0]; let LckC = findObjs({ characterid: char, name: "Lck_bd"})[0]; let DefC = findObjs({ characterid: char, name: "Def_bd"})[0]; let ResC = findObjs({ characterid: char, name: "Res_bd"})[0]; let HitC = findObjs({ characterid: char, name: "Hitmod"})[0]; let CritC = findObjs({ characterid: char, name: "Critmod"})[0]; let AvoC = findObjs({ characterid: char, name: "Avomod"})[0]; let DdgC = findObjs({ characterid: char, name: "Ddgmod"})[0]; //numerical stats let HPcurrStat = getAttrByName(char, 'HP_current'); let StrStat = getAttrByName(char, 'Str_total'); let MagStat = getAttrByName(char, 'Mag_total'); let SklStat = getAttrByName(char, 'Skl_total'); let SpdStat = getAttrByName(char, 'Spd_total'); let LckStat = getAttrByName(char, 'Lck_total'); let DefStat = getAttrByName(char, 'Def_total'); let ResStat = getAttrByName(char, 'Res_total'); let HitStat = getAttrByName(char, 'Hit'); let CritStat = getAttrByName(char, 'Crit'); let AvoStat = getAttrByName(char, 'Avo'); let DdgStat = getAttrByName(char, 'Ddg'); effect = eval(obj.radius_effect); //effect MUST be an array!!! rad_effect = Number(effect[0].get("current")) + parseInt(Number(effect[1])) log(effect[0].get("current")) effect[0].setWithWorker({ current: rad_effect }); log(effect[0].get("current")) if ((effect[0] == HPcurrC) && (char == attacker.id)){ HPA += parseInt(effect[1]) } if ((effect[0] == HPcurrC) && (char == defender.id)){ HPB += parseInt(effect[1]) } } } //recursionnn if (obj.children_skills != []){ for (var y in obj.children_skills){ Child_Skill = JSON.parse(obj.children_skills[y]); Skill(userid, targetid, Child_Skill, "any"); //child implementations of preexisting skills should have the triggertime "any" as well } } //Attack multiplier for stuff like Astra if (obj.attack_multiplier != 0){ if (userid == attacker.id){ for (i = 0; i < obj.attack_multiplier; i++){ if (randomInteger(100) < (HitA - AvoB)){ Chatstr += AName + "'s attack hits! \n"; //Check if attack crits if (randomInteger(100) < (CritA - DdgB)){ DmgA *= 3; Chatstr += AName+ " crits! \n"; } HPB -= DmgA; log("Damage is " + DmgA); CurrHPB.set("current", HPB); CWRVal += 2; CurrWR.set("current",CWRVal); log("Incremented weapon EXP!"); DecUsesA(); log("Decreased weapon uses!"); } else { Chatstr += AName+ " misses! \n"; } } DoubleA = false; } else { for (i = 0; i < obj.attack_multiplier; i++){ if (randomInteger(100) < (HitB - AvoA)){ Chatstr += DName+ "'s attack hits!"; //Check if attack crits if (randomInteger(100) < (CritB - DdgA)){ DmgB *= 3; Chatstr += "\n"+ DName+ " crits!"; } HPA -= DmgB; CurrHPA.set("current", HPA); //Defender gets no WEXP to discourage turtling on EP DecUsesB(); log("Decreased weapon uses!"); } else { Chatstr += DName+ " misses!"; } } DoubleB = false; } } Chatstr += obj.name + " activated!\n" } //more conditional checks if (obj.e_physmagcond != false){ if ((obj.e_physmagcond == "Physical" && DmgtypeE == "Magical") || (obj.e_physmagcond == "Magical" && DmgtypeE == ("Physical" || "Firearm"))){ return; } } if (obj.u_physmagcond != false){ if ((obj.u_physmagcond == "Physical" && DmgtypeU == "Magical") || (obj.u_physmagcond == "Magical" && DmgtypeU == ("Physical" || "Firearm"))){ return; } } if (obj.killcond == true){ //this should only be true if the triggertime is after if (CurrHPE.get("current") > 0){ return; } } if (obj.rng != "none") { if (randomInteger(100) < (rng * obj.rngmod)) { skillMain(); } else { log("RIP RNG") return; } } else { //Plain ol' skill trigger log("Regular skillmain") skillMain(); } } else { log(triggertime + " vs " + obj.triggertime); log("Attacker id is " + attacker.id + "; Defender id is " + defender.id); log("Userid is" + userid); log("Whotriggered is " + obj.whotriggered); return; }}; //I know it looks weird, but don't touch this! //before triggers for (i in SkillsA){ Skill(attacker.id, defender.id, SkillsA[i], "before"); } for (i in SkillsB){ Skill(defender.id, attacker.id, SkillsB[i], "before"); } //Actual battle script //Check if attacker's attack hits/is in range let AXCoord = selectedToken.get("left"); let AYCoord = selectedToken.get("top"); let BXCoord = targetToken.get("left"); let BYCoord = targetToken.get("top"); let diff = parseInt((Math.abs(AXCoord - BXCoord))+(Math.abs(AYCoord - BYCoord))); log(diff/70 + " tiles away!"); let css = { attack: 'style = "color: #353535"' }; if (CanAttackA == true) { if (((Range1A) <= (diff/70)) && ((diff/70) <= (Range2A))){ Chatstr += AName+ "'s attack is in range! \n"; if (randomInteger(100) < (HitA - AvoB)){ Chatstr += AName + "'s attack hits! \n"; //Battle skill trigger for (i in SkillsA){ Skill(attacker.id, defender.id, SkillsA[i], "during"); } //Check if attack crits if (randomInteger(100) < (CritA - DdgB)){ DmgA *= 3; Chatstr += AName+ " crits! \n"; } HPB -= DmgA; log("Damage is " + DmgA); CurrHPB.set("current", HPB); CWRVal += 2; CurrWR.set("current",CWRVal); log("Incremented weapon EXP!"); DecUsesA(); log("Decreased weapon uses!"); } else { Chatstr += AName+ " misses! \n"; } } else { Chatstr += AName + "'s attack is not in range! \n"; } } else { Chatstr += AName +" cannot attack!"; } if (CanAttackB == true){ //Check if defender's attack hits if (((Range1B) <= (diff/70)) && ((diff/70) <= (Range2B))){ Chatstr += DName + "'s attack is in range! \n"; if (randomInteger(100) < (HitB - AvoA)){ Chatstr += DName+ "'s attack hits!"; //battle skill trigger for (i in SkillsB){ Skill(defender.id, attacker.id, SkillsB[i], "before"); } //Check if attack crits if (randomInteger(100) < (CritB - DdgA)){ DmgB *= 3; Chatstr += "\n"+ DName+ " crits!"; } HPA -= DmgB; CurrHPA.set("current", HPA); //Defender gets no WEXP to discourage turtling on EP DecUsesB(); log("Decreased weapon uses!"); } else { Chatstr += DName+ " misses!"; } } else { Chatstr += DName + "'s attack is not in range!"; } } else { Chatstr += "\n"+ DName +" cannot attack!"; } //Attacker doubles; I don't think I should need to do usability checking for doubleattacking since it's checked within the battle calc if ((DoubleA === true) && (CanAttackA == true)){ Chatstr += "\n"+ AName+ " doubleattacks! \n"; if (randomInteger(100) < (HitA - AvoB)){ Chatstr += AName+ "'s attack hits!"; for (i in SkillsA){ Skill(attacker.id, defender.id, SkillsA[i], "during"); } //Check if attack crits if (randomInteger(100) < (CritA - DdgB)){ DmgA *= 3; Chatstr += "\n"+ AName+ " crits!"; } HPB -= DmgA; CurrHPB.set("current", HPB); CWRVal += 2; CurrWR.set("current",CWRVal); log("Incremented weapon EXP!"); DecUsesA(); log("Decreased weapon uses!"); } else { Chatstr += AName+ " misses!"; } if (QuadA === true){ Chatstr += AName+ " tripleattacks! \n"; if (randomInteger(100) < (HitA - AvoB)){ Chatstr += AName+ "'s attack hits! \n"; for (i in SkillsA){ Skill(attacker.id, defender.id, SkillsA[i], "during"); } //Check if attack crits if (randomInteger(100) < (CritA - DdgB)){ DmgA *= 3; Chatstr += AName+ " crits! \n"; } HPB -= DmgA; CurrHPB.set("current", HPB); CWRVal += 2; CurrWR.set("current",CWRVal); log("Incremented weapon EXP!"); DecUsesA(); log("Decreased weapon uses!"); } else { Chatstr += AName+ " misses! \n"; } Chatstr += AName+ " quadrupleattacks! \n"; if (randomInteger(100) < (HitA - AvoB)){ Chatstr += AName+ "'s attack hits! \n"; for (i in SkillsA){ Skill(attacker.id, defender.id, SkillsA[i], "during"); } //Check if attack crits if (randomInteger(100) < (CritA - DdgB)){ DmgA *= 3; Chatstr += AName+ " crits! \n"; } HPB -= DmgA; CurrHPB.set("current", HPB); CWRVal += 2; CurrWR.set("current",CWRVal); log("Incremented weapon EXP!"); DecUsesA(); log("Decreased weapon uses!"); } else { Chatstr += AName+ " misses!"; } } } //Defender doubles if ((DoubleB === true) && (CanAttackB == true)){ Chatstr += "\n"+ DName+ " doubleattacks! \n"; if (randomInteger(100) < (HitB - AvoA)){ Chatstr += DName+ "'s attack hits! \n"; for (i in SkillsB){ Skill(defender.id, attacker.id, SkillsB[i], "during"); } //Check if attack crits if (randomInteger(100) < (CritB - DdgA)){ DmgB *= 3; Chatstr += DName+ " crits! \n"; } HPA -= DmgB; CurrHPA.set("current", HPA); DecUsesB(); log("Decreased weapon uses!"); } else { Chatstr += DName+ " misses! \n"; } if (QuadB === true){ Chatstr += DName+ " tripleattacks! \n"; if (randomInteger(100) < (HitB - AvoA)){ Chatstr += DName+ "'s attack hits! \n"; for (i in SkillsB){ Skill(defender.id, attacker.id, SkillsB[i], "during"); } //Check if attack crits if (randomInteger(100) < (CritB - DdgA)){ DmgB *= 3; Chatstr += DName+ " crits! \n"; } HPA -= DmgB; CurrHPA.set("current", HPA); DecUsesB(); log("Decreased weapon uses!"); } else { Chatstr += DName+ " misses! \n"; } Chatstr += DName+ " quadrupleattacks! \n"; if (randomInteger(100) < (HitB - AvoA)){ Chatstr += DName+ "'s attack hits! \n"; for (i in SkillsB){ Skill(defender.id, attacker.id, SkillsB[i], "during"); } //Check if attack crits if (randomInteger(100) < (CritB - DdgA)){ DmgB *= 3; Chatstr += DName+ " crits! \n"; } HPA -= DmgB; CurrHPA.set("current", HPA); DecUsesB(); log("Decreased weapon uses!"); } else { Chatstr += DName+ " misses!"; } } } //after triggers for (i in SkillsA){ Skill(attacker.id, defender.id, SkillsA[i], "after"); } for (i in SkillsB){ Skill(defender.id, attacker.id, SkillsB[i], "after"); } sendChat(who,'